#include "mainwindow.h"
#include <QMessageBox>
#include <QDateTime>
#include <QThread>

MainWindow::MainWindow(QWidget *parent)
    : QWidget(parent) {
    setupUI();

    udpSocket = new QUdpSocket(this);
    if(!udpSocket->bind(QHostAddress::AnyIPv4, 0)) {
        QMessageBox::critical(this, "Error", "Failed to bind UDP socket!");
    }

    connect(udpSocket, &QUdpSocket::readyRead, this, &MainWindow::readPendingDatagrams);
}

MainWindow::~MainWindow() {
    udpSocket->close();
}

void MainWindow::setupUI() {
    QVBoxLayout *mainLayout = new QVBoxLayout(this);

    QHBoxLayout *regLayout = new QHBoxLayout();
    usernameEdit = new QLineEdit(this);
    usernameEdit->setPlaceholderText("用户名");
    registerBtn = new QPushButton("注册", this);
    regLayout->addWidget(usernameEdit);
    regLayout->addWidget(registerBtn);

    QHBoxLayout *connLayout = new QHBoxLayout();
    targetEdit = new QLineEdit(this);
    targetEdit->setPlaceholderText("目标用户名");
    connectBtn = new QPushButton("连接", this);
    connLayout->addWidget(targetEdit);
    connLayout->addWidget(connectBtn);

    chatDisplay = new QTextEdit(this);
    chatDisplay->setReadOnly(true);

    QHBoxLayout *msgLayout = new QHBoxLayout();
    messageEdit = new QLineEdit(this);
    messageEdit->setPlaceholderText("输入消息");
    sendBtn = new QPushButton("发送", this);
    msgLayout->addWidget(messageEdit);
    msgLayout->addWidget(sendBtn);

    mainLayout->addLayout(regLayout);
    mainLayout->addLayout(connLayout);
    mainLayout->addWidget(chatDisplay);
    mainLayout->addLayout(msgLayout);

    connect(registerBtn, &QPushButton::clicked, this, &MainWindow::onRegisterClicked);//注册
    connect(connectBtn, &QPushButton::clicked, this, &MainWindow::onConnectClicked);//连接对方
    connect(sendBtn, &QPushButton::clicked, this, &MainWindow::onSendClicked);//发送消息
}

void MainWindow::onRegisterClicked() {
    QString username = usernameEdit->text().trimmed();
    if(username.isEmpty()) {
        QMessageBox::warning(this, "警告", "用户名不能为空");
        return;
    }

    QByteArray message = "REGISTER " + username.toUtf8();
    udpSocket->writeDatagram(message, serverAddr, serverPort);
}

void MainWindow::onConnectClicked() {
    QString targetUser = targetEdit->text().trimmed();
    QString sourceUser = usernameEdit->text().trimmed();

    if(targetUser.isEmpty() || sourceUser.isEmpty()) {
        QMessageBox::warning(this, "警告", "用户名和目标用户不能为空");
        return;
    }

    // 格式：TARGET:源用户:目标用户
    QString message = "TARGET:" + sourceUser + ":" + targetUser;
    udpSocket->writeDatagram(message.toUtf8(), serverAddr, serverPort);
}

void MainWindow::onSendClicked() {
    if(peerPort == 0) {
        QMessageBox::warning(this, "警告", "请先连接目标用户");
        return;
    }

    QString msg = messageEdit->text().trimmed();
    if(msg.isEmpty()) return;

    QByteArray data = msg.toUtf8();
    udpSocket->writeDatagram(data, peerAddr, peerPort);
    qDebug() << peerAddr <<" " <<peerPort;
    chatDisplay->append(QString("[%1] 我: %2")
                            .arg(QDateTime::currentDateTime().toString("hh:mm:ss"))
                            .arg(msg));
    messageEdit->clear();
}

void MainWindow::readPendingDatagrams() {
    while(udpSocket->hasPendingDatagrams()) {
        QByteArray datagram;
        datagram.resize(udpSocket->pendingDatagramSize());
        QHostAddress sender;
        quint16 senderPort;

        udpSocket->readDatagram(datagram.data(), datagram.size(), &sender, &senderPort);

        if(sender == serverAddr && senderPort == serverPort) {
            handleServerResponse(datagram, sender, senderPort);
        } else {
            handlePeerMessage(datagram);
        }
    }
}

void MainWindow::handleServerResponse(const QByteArray &data, const QHostAddress &sender, quint16 port) {
    QString response = QString::fromUtf8(data);
    qDebug() << "服务器响应:" << response;

    if(response.startsWith("ERROR")) {
        QMessageBox::critical(this, "错误", response);
        return;
    }

    if(response == "REGISTER_OK") {
        chatDisplay->append("✓ 注册成功\n本地端口: " +
                            QString::number(udpSocket->localPort()));
    }
    else if(response.startsWith("PUNCH:")) {
        QStringList parts = response.mid(6).split(':');
        if(parts.size() == 2) {
            QHostAddress addr(parts[0]);
            quint16 port = parts[1].toUShort();

            for(int i=0; i<5; i++) {
                udpSocket->writeDatagram("PUNCH_REQ", addr, port);
                QThread::msleep(200);
            }
            chatDisplay->append("⇨ 正在向 " + addr.toString() +
                                ":" + QString::number(port) + " 打洞");
        }
    }
    else if(response.contains(':')) {
        QStringList parts = response.split(':');
        if(parts.size() == 2) {
            peerAddr = QHostAddress(parts[0]);
            peerPort = parts[1].toUShort();

            for(int i=0; i<5; i++) {
                udpSocket->writeDatagram("PUNCH_INIT", peerAddr, peerPort);
                QThread::msleep(200);
            }
            chatDisplay->append("⇌ 连接目标: " +
                                peerAddr.toString() + ":" +
                                QString::number(peerPort));
        }
    }
}

void MainWindow::handlePeerMessage(const QByteArray &data) {
    QString msg = QString::fromUtf8(data);

    if(msg == "PUNCH_INIT") {
        chatDisplay->append("收到初始化打洞包，通道已建立");
        return;
    }
    if(msg == "PUNCH_REQ") {
        chatDisplay->append("收到打洞请求，正在响应...");
        udpSocket->writeDatagram("PUNCH_ACK", peerAddr, peerPort);
        return;
    }
    if(msg == "PUNCH_ACK") {
        chatDisplay->append("打洞确认收到，通道就绪");
        return;
    }

    chatDisplay->append(QString("[%1] 对方: %2")
                            .arg(QDateTime::currentDateTime().toString("hh:mm:ss"))
                            .arg(msg));
}

void MainWindow::timerEvent(QTimerEvent *event) {
    QString status = QString("本地端口: %1 | 对端: %2:%3")
                         .arg(udpSocket->localPort())
                         .arg(peerAddr.toString())
                         .arg(peerPort);
    //statusBar()->showMessage(status);
}
